package com.abel.bigwater.dataserver.model.qdies

import com.abel.bigwater.data.BcdString
import com.abel.bigwater.dataserver.model.PacketCmdException
import io.netty.buffer.ByteBuf

class MainPacket {
    companion object {
        const val MIN_LEN = 1 + 4 + 1 + 1 + 1 + 1
        val DUMMY_FILL = byteArrayOf(0xFE.toByte(), 0xFE.toByte())
    }

    val head = 0x68

    var dummy = true

    var address: BcdString? = null

    var func: FuncType? = null

    /**
     * 1 byte
     */
    var dataLen: Int? = null

    var data: D10BaseData? = null

    var crc: Byte? = null

    val tail = 0x16

    var text: String? = null

    var index: Int? = null

    fun fill(buf: ByteBuf) {
        when (func) {
            FuncType.Heart -> assert(data is MainHeartData)
            FuncType.Login -> assert(data is MainLoginData)
            FuncType.AskState -> assert(data is MainAskStateData)

            FuncType.AskTime -> assert(data is MainAskTimeData)
            FuncType.SetTime -> assert(data is MainSetTimeData)

            FuncType.AskIpPort -> assert(data is MainAskIpPortData)
            FuncType.SetIpPort -> assert(data is MainSetIpPortData)

            FuncType.SetPulseBase -> assert(data is MainPulseBaseData)

            FuncType.SetActiveOnline -> assert(data is MainSetActiveOnlineData)
            FuncType.AskActiveOnline -> assert(data is MainAskActiveOnlineData)

            FuncType.SetUploadMode -> assert(data is MainSetUploadModeData)
            FuncType.AskUploadMode -> assert(data is MainAskUploadModeData)

            FuncType.AskMeterConfig -> assert(data is MainAskMeterConfigData)
            FuncType.Ask485Config -> assert(data is MainAsk485ConfigData)
            FuncType.AskAnalogConfig -> assert(data is MainAskAnalogConfigData)
            FuncType.AskPulseConfig -> assert(data is MainAskPulseConfigData)

            FuncType.SetMeterConfig -> assert(data is MainSetMeterConfigData)
            FuncType.Config485 -> assert(data is MainConfig485Data)
            FuncType.ConfigAnalog -> assert(data is MainConfigAnalogData)
            FuncType.ConfigPulse -> assert(data is MainConfigPulseData)

            FuncType.Ask485Hist -> assert(data is MainAsk485HistData)
            FuncType.AskAnalogHist -> assert(data is MainAskAnalogHistData)
            FuncType.AskPulseHist -> assert(data is MainAskPulseHistData)

            FuncType.Ask485Now -> assert(data is MainAsk485NowData)
            FuncType.AskAnalogNow -> assert(data is MainAskAnalogNowData)
            FuncType.AskPulseNow -> assert(data is MainAskPulseNowData)

            FuncType.ClearWarn -> assert(data is MainClearWarnData)

            else -> throw PacketCmdException("unknown data: ${data}")
        }

        buf.writeBytes(buf.alloc().buffer().apply {
            if (dummy) {
                writeBytes(DUMMY_FILL)
            }
            writeByte(head)

            writeBytes(address!!.hexArray)
            writeByte(func!!.code.toInt())

            dataLen = data!!.count()
            writeByte(dataLen!!.toInt())
            data!!.fill(this)

            val tmp = this.duplicate()
            crc = (0x100 - ByteArray(tmp.readableBytes()).also { tmp.readBytes(it) }.sum()).and(0xFF).toByte()
            writeByte(crc!!.toInt())
            writeByte(tail)

            if (index != null) {
                writeShort(index!!)
            }
        })
    }

    fun parse(buf: ByteBuf): Boolean {
        TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
    }
}